package jlib.component.button
{
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	
	public class SkinButton extends Sprite implements IButton {
		
		private var m_map:Object;
		private var m_delegate:Sprite;
		
		private var m_isSelected:Boolean;
		private var m_isToggle:Boolean;
		
		private var m_strategy:IButtonStrategy;
		private var m_buttonStrategy:IButtonStrategy;
		private var m_toggleStrategy:IButtonStrategy;
		
		public function SkinButton($delegate:Sprite=null) {
			init();
			buttonMode = true;
			m_delegate = $delegate;
			if(m_delegate){
				setWrappee(m_delegate);
			}  else{
				setWrappee(this);
			}
		}
		
		public function init(): void {
			m_map = new Object;
			m_buttonStrategy = new DefaultStrategy(this);
			setToggle(false);
			mouseChildren = false;
		}
		
		// behavior
		public function setSkin($state:String, $value:DisplayObject): void {
			m_map[$state] = $value;
			m_delegate.addEventListener(MouseEvent.CLICK, click );
			if($state == ButtonState.DOWN) m_delegate.addEventListener(MouseEvent.MOUSE_DOWN, down );
			if($state == ButtonState.ROLLOVER) m_delegate.addEventListener(MouseEvent.ROLL_OVER, rollOver );
			if($state == ButtonState.ROLLOUT) m_delegate.addEventListener(MouseEvent.ROLL_OUT, rollOut );
			if($state == ButtonState.UP) m_delegate.addEventListener(MouseEvent.MOUSE_UP, up );
			if(hasState(ButtonState.UP)) view(ButtonState.UP);
			this.addChild($value);
		}
		
		public function setToggle(boolean:Boolean): void {
			m_isToggle = boolean;
			if(boolean) {
				if(!m_toggleStrategy) m_toggleStrategy = new ToggleStrategy(this);
				changeStratey(m_toggleStrategy);
			} else changeStratey(m_buttonStrategy);
		}
		
		public function down(e:Event=null): void {
			m_strategy.down(e);
			if(m_delegate.stage) {
				m_delegate.stage.addEventListener(MouseEvent.MOUSE_UP, outside );
				m_delegate.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onCheckOutside );
				m_delegate.removeEventListener(MouseEvent.ROLL_OVER, rollOver );
				m_delegate.removeEventListener(MouseEvent.ROLL_OUT, rollOut );
			}
		}
		
		public function up(e:Event=null): void {
			m_strategy.up(e);
		}
		
		public function click(e:Event=null): void {
			m_strategy.click(e);
		}
		
		public function toggle(e:Event=null): void {
			click();
		}
		
		internal function rollOver(e:Event=null): void {
			if(m_delegate.hasEventListener(MouseEvent.ROLL_OUT)){
				if(m_delegate.stage) m_delegate.stage.addEventListener(MouseEvent.MOUSE_MOVE, onCheckOutside );
			}
			m_strategy.rollOver(e);
		}
		
		internal function rollOut(e:Event=null): void {
			m_delegate.removeEventListener(MouseEvent.MOUSE_MOVE, onCheckOutside );
			m_strategy.rollOut(e);
		}
		
		internal function outside(e:Event=null): void {
			m_strategy.outside(e);
			if(m_delegate.stage) {
				m_delegate.stage.removeEventListener(MouseEvent.MOUSE_UP, outside );
				m_delegate.addEventListener(MouseEvent.ROLL_OVER, rollOver );
				m_delegate.addEventListener(MouseEvent.ROLL_OUT, rollOut );
				if(!isTogglable()) dispatchEvent(new Event(MouseEvent.MOUSE_UP));
			}
		}
		
		private function onCheckOutside($event:Event): void {
			if(m_delegate != $event.target) {
				m_delegate.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onCheckOutside );
				rollOut($event);
			}
		}
		
		public function changeStratey($buttonStrategy:IButtonStrategy): void {
			m_strategy = $buttonStrategy;
		}
		
		public function view($state:String): void {
			for each(var viewState:* in m_map){
				if(m_map.hasOwnProperty($state)) viewState.visible = false;
			}
			if(m_map.hasOwnProperty($state)) m_map[$state].visible = true;
		}
		
		public function hasState($state:String): Boolean { return Boolean(m_map[$state]);}
		
		public function setWrappee(sprite:Sprite): void { m_delegate = sprite; }
		
		public function isTogglable():Boolean  {  return m_isToggle;  }
		public function isSelected():Boolean {  return m_strategy.isSelected();  }
	}//c
}